using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public enum ControlState
{
    ecs_None,               // 空闲
    ecs_Ground,             // 操作地板
    ecs_BuildingWall,
    ecs_BuildingWoodenWall, // 木墙
    ecs_Goods,              // 家具

    ecs_Del,                // 删除
}

public class StateManager {

    private static StateManager mInstance;
	struct GoodsSize
	{
		public int w;
		public int h;
	}
	class ModelData
	{
		public string modelName;
		public int startX = 0;
		public int startZ = 0;
		public int numX = 1;
		public int numZ = 1;
		public int rotate = 0;
		public float offsetX = 0.5f;
		public float offsetZ = 0.5f;
		
		public void Clean()
		{
			modelName = "";
			startX = 0;
			startZ = 0;
			numX = 1;
			numZ = 1;
			rotate = 0;
			offsetX = 0.5f;
			offsetZ = 0.5f;
		}

		public void SetData(ModelData src)
		{
			modelName = src.modelName;
			startX = src.startX;
			startZ = src.startZ;
			numX = src.numX;
			numZ = src.numZ;
			rotate = src.rotate;
			offsetX = src.offsetX;
			offsetZ = src.offsetZ;
		}
	}
    private int m_nMapSize = 500;	// 场景大小
    private GameObject[,] selObj = null;
	private ModelData curModelData = new ModelData();
	private ModelData nextModelData = new ModelData();
	private InputController IC;
	private GameObject MyGroundBox;
	struct NormalData
	{
		public string fileName;
		public string modelFile;
	}
	struct GoodsData
	{
		public string fileName;
		public string modelFile;
		public int nWidth;
		public int nHeight;
	}

	private ControlState curSelState = ControlState.ecs_None;
    private int m_selIndex = 0;
    private NormalData[] m_groundList;	// 地板列表
    private int m_curGroundRotate = 0;// 当前角度
    private NormalData[] m_wallList;	// 墙列表
    private int m_curWallRotate = 0;// 当前角度
    private GoodsData[] m_goodsList;	// 物件列表
    private int m_curGoodsRotate = 0;	// 当前物件角度
    private bool[] m_isGoodsSingular = {false, false};// 长宽是否单数
    int nStartX = -1;
    int nStartZ = -1;
    int nEndX = -1;
    int nEndZ = -1;
	bool isLButtonDown = false;
	bool isRButtonDown = false;
	bool isRKeyDown = false;
    //单例
    public static StateManager GetInstance()
    {
        if (mInstance == null)
        {
            mInstance = new StateManager();
			mInstance.Init();
        }
        return mInstance;
    }
    private StateManager()
    {
        mInstance = this;
    }

	void LoadGroundList()
	{
        uint nCount = DBCManager.GetInstance().GetGroundDBC().GetRecordCount( );
        m_groundList = new NormalData[nCount];
        for(uint i = 0; i < nCount; i++)
        {
            m_groundList[i] = new NormalData();
			m_groundList[i].fileName = DBCManager.GetInstance().GetGroundDBC().GetString(i, 0);
			m_groundList[i].modelFile = DBCManager.GetInstance().GetGroundDBC().GetString(i, 1);
        }
	}
	void LoadWallList()
	{
        uint nCount = DBCManager.GetInstance().GetWoodenWallDBC().GetRecordCount( );
        m_wallList = new NormalData[nCount];
        for(uint i = 0; i < nCount; i++)
        {
            m_wallList[i] = new NormalData();
            m_wallList[i].fileName = DBCManager.GetInstance().GetWoodenWallDBC().GetString(i, 0);
			m_wallList[i].modelFile = DBCManager.GetInstance().GetWoodenWallDBC().GetString(i, 1);
        }
	}
	void LoadGoodsList()
	{
        uint nCount = DBCManager.GetInstance().GetOtherDBC().GetRecordCount( );
        m_goodsList = new GoodsData[nCount];
        for(uint i = 0; i < nCount; i++)
        {
            m_goodsList[i] = new GoodsData();
            m_goodsList[i].fileName = DBCManager.GetInstance().GetOtherDBC().GetString(i, 0);
			m_goodsList[i].modelFile = DBCManager.GetInstance().GetOtherDBC().GetString(i, 1);
            m_goodsList[i].nWidth = DBCManager.GetInstance().GetOtherDBC().GetInt(i, 2);
            m_goodsList[i].nHeight = DBCManager.GetInstance().GetOtherDBC().GetInt(i, 3);
        }
	}
	public void Init () {
		MyGroundBox = GameObject.Find("MyGroundBox");
		IC = GameObject.Find("CONTROL").GetComponent<InputController>() as InputController;

        GridManager.GetInstance().SetMapSize(m_nMapSize);
		
		LoadGroundList();
		LoadWallList();
		LoadGoodsList();

		// 初始创建4块陆地
		GridManager.GetInstance().AddGround(m_groundList[0].fileName, m_nMapSize/2-1, m_nMapSize/2-1);
		GridManager.GetInstance().AddGround(m_groundList[0].fileName, m_nMapSize/2-1, m_nMapSize/2);
		GridManager.GetInstance().AddGround(m_groundList[0].fileName, m_nMapSize/2, m_nMapSize/2-1);
		GridManager.GetInstance().AddGround(m_groundList[0].fileName, m_nMapSize/2, m_nMapSize/2);
	}
	void OnLButtonDown()
	{		
		switch(curSelState)
		{
			case ControlState.ecs_Ground:
			case ControlState.ecs_BuildingWoodenWall:
			case ControlState.ecs_Goods:
			{
				Ray worldRay = Camera.main.ScreenPointToRay (Input.mousePosition);
				RaycastHit hitInfo = new RaycastHit();
				if (Physics.Raycast(worldRay, out hitInfo, 10000.0f, GridManager.mGridListLayerMask))
				{					
					// 从世界坐标--》plane坐标
					Vector3 localPos = MyGroundBox.transform.InverseTransformPoint(hitInfo.point);
					nextModelData.startX = nStartX = (int)localPos.x;
					nextModelData.startZ = nStartZ = (int)localPos.z;
					nextModelData.numX = 1;
					nextModelData.numZ = 1;
					UpdateCurModel();
				}
			}
			break;
		}
	}
	void OnLButtonUp()
	{		
		switch(curSelState)
		{
			case ControlState.ecs_Ground:
			case ControlState.ecs_BuildingWoodenWall:
			case ControlState.ecs_Goods:
			{
				if(nStartX < 0 || nStartZ < 0)
				{
					return;
				}
				Ray worldRay = Camera.main.ScreenPointToRay (Input.mousePosition);
				RaycastHit hitInfo = new RaycastHit();
				if (Physics.Raycast(worldRay, out hitInfo, 10000.0f, GridManager.mGridListLayerMask))
				{					
					Vector3 localPos = MyGroundBox.transform.InverseTransformPoint(hitInfo.point);
					nextModelData.startX = (int)localPos.x;
					nextModelData.startZ = (int)localPos.z;
					switch(curSelState)
					{
						case ControlState.ecs_Ground:
						case ControlState.ecs_BuildingWoodenWall:
						{
							int nTStartX, nTEndX;
							int nTStartZ, nTEndZ;
							if(nStartX < nextModelData.startX)
							{
								nTStartX = nStartX;
								nTEndX = nextModelData.startX;
							}
							else
							{
								nTStartX = nextModelData.startX;
								nTEndX = nStartX;
							}
							if(nStartZ < nextModelData.startZ)
							{
								nTStartZ = nStartZ;
								nTEndZ = nextModelData.startZ;
							}
							else
							{
								nTStartZ = nextModelData.startZ;
								nTEndZ = nStartZ;
							}
							int numX = nTEndX-nTStartX+1;
							int numZ = nTEndZ-nTStartZ+1;
							if(curSelState == ControlState.ecs_Ground)
							{						
								for(int z = 0; z < numZ; z++)
								{
									for(int x = 0; x < numX; x++)
									{
										GridManager.GetInstance().AddGround(m_groundList[m_selIndex].fileName, nTStartX+x, nTStartZ+z, nextModelData.rotate);
									}
								}
								nextModelData.rotate = m_curGroundRotate;
							}
							else
							{								
								if(numX >= numZ)
								{
									for(int x = 0; x < numX; x++)
									{
										GridManager.GetInstance().AddBuilding(ObjType.eot_WoodenWall, m_wallList[m_selIndex].fileName, nTStartX+x, nStartZ, nextModelData.rotate);
									}
								}
								else
								{			
									for(int z = 0; z < numZ; z++)
									{
										GridManager.GetInstance().AddBuilding(ObjType.eot_WoodenWall, m_wallList[m_selIndex].fileName, nStartX, nTStartZ+z, nextModelData.rotate);
									}
								}
								nextModelData.rotate = m_curWallRotate;
							}
							nextModelData.numX = 1;
							nextModelData.numZ = 1;
							UpdateCurModel();
						}
						break;						
						case ControlState.ecs_Goods:
						{
							GridManager.GetInstance().AddBuilding(ObjType.eot_Other, m_goodsList[m_selIndex].fileName, nextModelData.startX, nextModelData.startZ, nextModelData.rotate);
						}
						break;
					}
				}
			}
			break;
			case ControlState.ecs_Del:
			{
				Ray worldRay = Camera.main.ScreenPointToRay (Input.mousePosition);
				RaycastHit hitInfo = new RaycastHit();
				if (Physics.Raycast(worldRay, out hitInfo, 10000.0f, (GridManager.mGroundLayerMask|GridManager.mWallLayerMask|GridManager.mGoodsLayerMask)))
				{
					ObjProperty objProp = hitInfo.collider.gameObject.GetComponent<ObjProperty>();
					if(objProp)
					{
						GridManager.GetInstance().DelBuilding(objProp.nX, objProp.nZ, objProp.nIndex);
					}
				}
			}
			break;
		}
		
    	nStartX = -1;
    	nStartZ = -1;
    	nEndX = -1;
    	nEndZ = -1;
	}
	void OnRButtonDown()
	{
	}
	void OnRButtonUp()
	{
	}
	void OnMouseMove()
	{		
		switch(curSelState)
		{
			case ControlState.ecs_Ground:
			case ControlState.ecs_BuildingWoodenWall:
			{
				Vector3 curPos = Input.mousePosition;
				if(Input.mousePosition.x < 0 || Input.mousePosition.y < 0)
				{
					return;
				}
				Ray worldRay = Camera.main.ScreenPointToRay (Input.mousePosition);
				RaycastHit hitInfo = new RaycastHit();
				
				if (Physics.Raycast(worldRay, out hitInfo, 10000.0f, GridManager.mGridListLayerMask))
				{					
					Vector3 localPos = MyGroundBox.transform.InverseTransformPoint(hitInfo.point);
					if(isLButtonDown)
					{					
						nEndX = (int)localPos.x;
						nEndZ = (int)localPos.z;	
						int nTStartX, nTEndX;
						int nTStartZ, nTEndZ;
						if(nStartX < nEndX)
						{
							nTStartX = nStartX;
							nTEndX = nEndX;
						}
						else
						{
							nTStartX = nEndX;
							nTEndX = nStartX;
						}
						if(nStartZ < nEndZ)
						{
							nTStartZ = nStartZ;
							nTEndZ = nEndZ;
						}
						else
						{
							nTStartZ = nEndZ;
							nTEndZ = nStartZ;
						}
						if(curSelState == ControlState.ecs_Ground)
						{
							nextModelData.startX = nTStartX;
							nextModelData.startZ = nTStartZ;
							nextModelData.numX = nTEndX-nTStartX+1;
							nextModelData.numZ = nTEndZ-nTStartZ+1;
						}
						else
						{
							int distX = nTEndX-nTStartX;
							int distZ = nTEndZ-nTStartZ;
							if(distX >= distZ)
							{
								nextModelData.startX = nTStartX;
								nextModelData.startZ = nStartZ;
								nextModelData.numX = distX+1;
								nextModelData.numZ = 1;
							}
							else
							{
								nextModelData.startX = nStartX;
								nextModelData.startZ = nTStartZ;
								nextModelData.numX = 1;
								nextModelData.numZ = nTEndZ-nTStartZ+1;
							}
						}
					}
					else
					{
						nextModelData.startX = (int)localPos.x;
						nextModelData.startZ = (int)localPos.z;
					}
					UpdateCurModel();
				}
			}
			break;
			case ControlState.ecs_Goods:
			{
				Ray worldRay = Camera.main.ScreenPointToRay (Input.mousePosition);
				RaycastHit hitInfo = new RaycastHit();
				if (Physics.Raycast(worldRay, out hitInfo, 10000.0f, GridManager.mGridListLayerMask))
				{
					Vector3 localPos = MyGroundBox.transform.InverseTransformPoint(hitInfo.point);
					nextModelData.startX = (int)localPos.x;
					nextModelData.startZ = (int)localPos.z;
					UpdateCurModel();
				}
			}
			break;
			case ControlState.ecs_Del:
			{
			}
			break;
		}
	}
	void Turn()
	{		
		switch(curSelState)
		{
			case ControlState.ecs_Ground:
			{
				m_curGroundRotate++;
				if(m_curGroundRotate > 3)
				{
					m_curGroundRotate = 0;
				}
				nextModelData.rotate = m_curGroundRotate;
				UpdateCurModel();
			}
			break;
			case ControlState.ecs_BuildingWoodenWall:
			{
				m_curWallRotate++;
				if(m_curWallRotate > 3)
				{
					m_curWallRotate = 0;
				}
				nextModelData.rotate = m_curWallRotate;
				
				if(nextModelData.rotate == 0 || nextModelData.rotate == 2)
				{
					nextModelData.offsetX = 1.0f;
					nextModelData.offsetZ = 0.5f;
				}
				else
				{
					nextModelData.offsetX = 0.5f;
					nextModelData.offsetZ = 1.0f;
				}
				UpdateCurModel();
			}
			break;
			case ControlState.ecs_Goods:
			{
				m_curGoodsRotate++;
				if(m_curGoodsRotate > 3)
				{
					m_curGoodsRotate = 0;
				}
				nextModelData.rotate = m_curGoodsRotate;

				if(nextModelData.rotate == 0 || nextModelData.rotate == 2)      
				{
					m_isGoodsSingular[0] = m_goodsList[m_selIndex].nWidth%2 == 1;
					m_isGoodsSingular[1] = m_goodsList[m_selIndex].nHeight%2 == 1;
				}
				else
				{            
					m_isGoodsSingular[0] = m_goodsList[m_selIndex].nHeight%2 == 1;
					m_isGoodsSingular[1] = m_goodsList[m_selIndex].nWidth%2 == 1;
				}
				nextModelData.offsetX = m_isGoodsSingular[0]?0.5f:1.0f;
				nextModelData.offsetZ = m_isGoodsSingular[1]?0.5f:1.0f;
				UpdateCurModel();
			}
			break;
		}
	}
	public void FixedUpdate(){
		// 点左键
		if (IC.inputLMouse)
        {
			if(!isLButtonDown)
			{
				OnLButtonDown();
				isLButtonDown = true;
			}
        }
		else if(isLButtonDown)
		{
			OnLButtonUp();
			isLButtonDown = false;
		}
		// 点右键
		if (IC.inputRMouse)
        {
			if(!isRButtonDown)
			{
				OnRButtonDown();
				isRButtonDown = true;
			}
        }
		else if(isRButtonDown)
		{
			OnRButtonUp();
			isRButtonDown = false;
		}
		// 鼠标移动
		OnMouseMove();
		if(IC.inputKeyR)
		{
			if(!isRKeyDown)
			{
				isRKeyDown = true;
			}
		}
		else if(isRKeyDown)
		{
			Turn();
			isRKeyDown = false;
		}
	}
	public void UpdateCurModel()
	{
		if(nextModelData.modelName == "")
		{
			nextModelData.Clean();
			if(selObj != null)
			{
				for(int z = 0; z < curModelData.numZ; z++)
				{
					for(int x = 0; x < curModelData.numX; x++)
					{
						if(selObj[z,x]) GameObject.DestroyImmediate(selObj[z,x]);
					}
				}
			}
			selObj = null;
			curModelData.SetData(nextModelData);
			return;
		}
		if(selObj == null || curModelData.modelName != nextModelData.modelName)
		{
			if(selObj != null)
			{
				for(int z = 0; z < curModelData.numZ; z++)
				{
					for(int x = 0; x < curModelData.numX; x++)
					{
						if(selObj[z,x]) GameObject.DestroyImmediate(selObj[z,x]);
					}
				}
			}
			selObj = new GameObject[nextModelData.numZ,nextModelData.numX];
			for(int z = 0; z < nextModelData.numZ; z++)
			{
				for(int x = 0; x < nextModelData.numX; x++)
				{
					GameObject temp = (GameObject)Resources.Load(nextModelData.modelName);
					selObj[z,x] = GameObject.Instantiate(temp);
					Collider collider = selObj[z,x].GetComponent<Collider>();
					collider.enabled = false;
					Vector3 pos = new Vector3();
					pos.x = nextModelData.startX+x+nextModelData.offsetX;
					pos.z = nextModelData.startZ+z+nextModelData.offsetZ;					
					pos = MyGroundBox.transform.TransformPoint(pos);

					selObj[z,x].transform.SetPositionAndRotation(pos, MyGroundBox.transform.rotation*GridData.s_Quaternion[nextModelData.rotate]);
				}
			}
		}
		else if(curModelData.numX != nextModelData.numX || curModelData.numZ != nextModelData.numZ)
		{
			GameObject[,] oldselObj = selObj;
			selObj = new GameObject[nextModelData.numZ,nextModelData.numX];
			Vector3 pos = new Vector3();
			for(int z = 0; z < nextModelData.numZ; z++)
			{
				for(int x = 0; x < nextModelData.numX; x++)
				{
					if(x < curModelData.numX && z < curModelData.numZ)
					{							
						selObj[z,x] = oldselObj[z,x];
					}
					else
					{
						GameObject temp = (GameObject)Resources.Load(nextModelData.modelName);
						selObj[z,x] = GameObject.Instantiate(temp);
						Collider collider = selObj[z,x].GetComponent<Collider>();
						collider.enabled = false;
					}
					pos.x = nextModelData.startX+x+nextModelData.offsetX;
					pos.z = nextModelData.startZ+z+nextModelData.offsetZ;					
					pos = MyGroundBox.transform.TransformPoint(pos);
					selObj[z,x].transform.SetPositionAndRotation(pos, MyGroundBox.transform.rotation*GridData.s_Quaternion[nextModelData.rotate]);
				}
			}
			if(curModelData.numX > nextModelData.numX)
			{
				for(int z = 0; z < curModelData.numZ; z++)
				{
					for(int x = nextModelData.numX; x < curModelData.numX; x++)
					{						
						if(oldselObj[z,x]) GameObject.DestroyImmediate(oldselObj[z,x]);
					}
				}
			}
			if(curModelData.numZ > nextModelData.numZ)
			{
				for(int z = nextModelData.numZ; z < curModelData.numZ; z++)
				{
					for(int x = 0; x < nextModelData.numX; x++)
					{
						if(oldselObj[z,x]) GameObject.DestroyImmediate(oldselObj[z,x]);
					}
				}
			}
		}
		else
		{
			for(int z = 0; z < nextModelData.numZ; z++)
			{
				for(int x = 0; x < nextModelData.numX; x++)
				{
					if(selObj[z,x])
					{						
						Vector3 pos = new Vector3();
						pos.x = nextModelData.startX+x+nextModelData.offsetX;
						pos.z = nextModelData.startZ+z+nextModelData.offsetZ;					
						pos = MyGroundBox.transform.TransformPoint(pos);
						selObj[z,x].transform.SetPositionAndRotation(pos, MyGroundBox.transform.rotation*GridData.s_Quaternion[nextModelData.rotate]);
					}
				}
			}
		}
		curModelData.SetData(nextModelData);
	}

    public void ChangeState(ControlState state, int nIndex)
    {
        isLButtonDown = false;
        isRButtonDown = false;
        isRKeyDown = false;
        switch(state)
        {
            case ControlState.ecs_None:
            {
                m_selIndex = nIndex;
                if(curSelState != state)
                {
                    curSelState = state;
                    nextModelData.Clean();
                }
                else
                {
                    return;
                }
            }
            break;
            case ControlState.ecs_Ground:
            {
                if(curSelState != state)
                {
                    curSelState = state;
                    nextModelData.startX = 0;
                    nextModelData.startZ = 0;
                    nextModelData.numX = 1;
                    nextModelData.numZ = 1;
                    nextModelData.rotate = m_curGroundRotate;
                    nextModelData.offsetX = 1.0f;
                    nextModelData.offsetZ = 1.0f;
                }
                else if(m_selIndex == nIndex)
                {
                    return;
                }
                m_selIndex = nIndex; 
                nextModelData.modelName = m_groundList[m_selIndex].modelFile;  
            }
            break;
            case ControlState.ecs_BuildingWoodenWall:
            {
                if(curSelState != state)
                {
                    curSelState = state;
                    nextModelData.startX = 0;
                    nextModelData.startZ = 0;
                    nextModelData.numX = 1;
                    nextModelData.numZ = 1;
                    nextModelData.rotate = m_curWallRotate;
                    
                    if(nextModelData.rotate == 0 || nextModelData.rotate == 2)
                    {
                        nextModelData.offsetX = 1.0f;
                        nextModelData.offsetZ = 0.5f;
                    }
                    else
                    {
                        nextModelData.offsetX = 0.5f;
                        nextModelData.offsetZ = 1.0f;
                    }
                }
                else if(m_selIndex == nIndex)
                {
                    return;
                }
                m_selIndex = nIndex;                 
                nextModelData.modelName = m_wallList[m_selIndex].modelFile;
            }
            break;
            case ControlState.ecs_Goods:
            {
                if(curSelState != state)
                {
                    curSelState = state;
                    nextModelData.startX = 0;
                    nextModelData.startZ = 0;
                    nextModelData.numX = 1;
                    nextModelData.numZ = 1;
                    nextModelData.rotate = m_curGoodsRotate;
                }
                else if(m_selIndex == nIndex)
                {
                    return;
                }
                m_selIndex = nIndex; 
                nextModelData.modelName = m_goodsList[m_selIndex].modelFile;
                if(nextModelData.rotate == 0 || nextModelData.rotate == 2)
                {
                    m_isGoodsSingular[0] = m_goodsList[m_selIndex].nWidth%2 == 1;
                    m_isGoodsSingular[1] = m_goodsList[m_selIndex].nHeight%2 == 1;
                }
                else
                {            
                    m_isGoodsSingular[0] = m_goodsList[m_selIndex].nHeight%2 == 1;
                    m_isGoodsSingular[1] = m_goodsList[m_selIndex].nWidth%2 == 1;
                }
                nextModelData.offsetX = m_isGoodsSingular[0]?0.5f:1.0f;
                nextModelData.offsetZ = m_isGoodsSingular[1]?0.5f:1.0f;
            }
            break;
            case ControlState.ecs_Del:
            {
                m_selIndex = nIndex;
                if(curSelState != state)
                {
                    curSelState = state;
                    nextModelData.Clean();
                }
                else
                {
                    return;
                }
            }
            break;
        }
        UpdateCurModel();
    }
}